﻿using System.Collections.Generic;
using System.Reflection;
using System.Windows;
using JetBrains.Annotations;
using MugenMvvmToolkit.Interfaces;
using MugenMvvmToolkit.Interfaces.Views;
using MugenMvvmToolkit.Models;
using MugenMvvmToolkit.Utils;
using MugenMvvmToolkit.ViewModels;
#if !NETFX_CORE
using System.Windows.Threading;
#else
using Windows.UI.Xaml;
#endif
#if TASKSUPPORT
using System.Threading.Tasks;

#endif

namespace MugenMvvmToolkit.Infrastructure
{
    /// <summary>
    ///     Represents the class that is used to initialize the IOC adapter.
    /// </summary>
    public class DefaultInitializationStrategy : IInitializationStrategy
    {
        #region Fields

        private readonly IViewModelSettings _settings;
        private readonly IList<Assembly> _viewAssemblies;

        #endregion

        #region Constructors


        /// <summary>
        ///     Initializes a new instance of the <see cref="DefaultInitializationStrategy" /> class.
        /// </summary>
        public DefaultInitializationStrategy(IList<Assembly> viewAssemblies = null)
        {
            _viewAssemblies = viewAssemblies;
        }

        /// <summary>
        ///     Initializes a new instance of the <see cref="DefaultInitializationStrategy" /> class.
        /// </summary>
        public DefaultInitializationStrategy([NotNull]IViewModelSettings settings, IList<Assembly> viewAssemblies = null)
            : this(viewAssemblies)
        {
            Should.NotBeNull(settings, "settings");
            _settings = settings;
            _viewAssemblies = viewAssemblies;
        }

        #endregion

        #region Properties

        /// <summary>
        ///     Gets the current <see cref="IIocAdapter" />.
        /// </summary>
        protected IIocAdapter IocAdapter { get; private set; }

        #endregion

        #region Implementation of IInitializationStrategy

        /// <summary>
        ///     Initializes the specified <see cref="IIocAdapter" />.
        /// </summary>
        public virtual void Initialize(IIocAdapter iocAdapter)
        {
            Should.NotBeNull(iocAdapter, "iocAdapter");
            IocAdapter = iocAdapter;
            iocAdapter.BindToBindingInfo(GetThreadManager);
            GlobalSettings.DefaultThreadManager = iocAdapter.Get<IThreadManager>();

            iocAdapter.BindToBindingInfo(GetViewMappingProvider);
            iocAdapter.BindToBindingInfo(GetViewModelWrapperProvider);
            iocAdapter.BindToBindingInfo(GetViewManager);
            iocAdapter.BindToBindingInfo(GetViewModelProvider);
            iocAdapter.BindToBindingInfo(GetMessageBoxProvider);

            iocAdapter.BindToBindingInfo(GetSettings);
            iocAdapter.BindToBindingInfo(GetDisplayNameProvider);
            iocAdapter.BindToBindingInfo(GetEventAggregator);
#if !WPF
            IocAdapter.BindToBindingInfo<IViewPageMappingProvider>(GetViewPageMappingProvider);
#endif
#if !NOVISUALSTATE
            IocAdapter.BindToBindingInfo(GetVisualStateManager);
#endif
        }

        #endregion

        #region Methods

#if !NOVISUALSTATE
        /// <summary>
        ///     Gets the <see cref="IVisualStateManager" /> which will be used by default.
        /// </summary>
        /// <returns>An instance of <see cref="IVisualStateManager" />.</returns>
        protected virtual BindingInfo<IVisualStateManager> GetVisualStateManager()
        {
            return
                BindingInfo<IVisualStateManager>.FromInstance(new VisualStateManager(GlobalSettings.DefaultThreadManager));
        }
#endif

        /// <summary>
        ///     Gets the <see cref="IDisplayNameProvider" /> which will be used by default.
        /// </summary>
        /// <returns>An instance of <see cref="IDisplayNameProvider" />.</returns>
        protected virtual BindingInfo<IDisplayNameProvider> GetDisplayNameProvider()
        {
            return BindingInfo<IDisplayNameProvider>.FromInstance(new DisplayNameProvider());
        }

        /// <summary>
        ///     Gets the <see cref="IViewMappingProvider" /> which will be used by default.
        /// </summary>
        /// <returns>An instance of <see cref="IViewMappingProvider" />.</returns>
        protected virtual BindingInfo<IViewMappingProvider> GetViewMappingProvider()
        {
            return BindingInfo<IViewMappingProvider>.FromInstance(new AttributeViewMappingProvider(GetViewAssemblies()));
        }

#if !WPF
        /// <summary>
        /// Gets the <see cref="IViewPageMappingProvider"/> which will be used by default.
        /// </summary>
        /// <returns>An instance of <see cref="IViewPageMappingProvider"/>.</returns>
        protected virtual BindingInfo<IViewPageMappingProvider> GetViewPageMappingProvider()
        {
            return BindingInfo<IViewPageMappingProvider>.FromInstance(new AttributeViewPageMappingProvider(GetViewAssemblies()));
        }
#endif

        /// <summary>
        ///     Gets the <see cref="IViewManager" /> which will be used in all view models by default.
        /// </summary>
        /// <returns>An instance of <see cref="IViewManager" />.</returns>
        protected virtual BindingInfo<IViewManager> GetViewManager()
        {
            return
                BindingInfo<IViewManager>.FromInstance(new ViewManager(MvvmUtilsInternal.CanInitializeView,
                    IocAdapter.Get<IViewMappingProvider>()));
        }

        /// <summary>
        ///     Gets the <see cref="IViewModelProvider" /> which will be used in all view models by default.
        /// </summary>
        /// <returns>An instance of <see cref="IViewModelProvider" />.</returns>
        protected virtual BindingInfo<IViewModelProvider> GetViewModelProvider()
        {
            return BindingInfo<IViewModelProvider>.FromInstance(new ViewModelProvider(IocAdapter));
        }

        /// <summary>
        ///     Gets the <see cref="IMessageBox" /> which will be used in all view models by default.
        /// </summary>
        /// <returns>An instance of <see cref="IMessageBox" />.</returns>
        protected virtual BindingInfo<IMessageBox> GetMessageBoxProvider()
        {
            return BindingInfo<IMessageBox>.Empty;
        }

        /// <summary>
        ///     Gets the <see cref="IThreadManager" /> which will be used in all view models by default.
        /// </summary>
        /// <returns>An instance of <see cref="IThreadManager" />.</returns>
        protected virtual BindingInfo<IThreadManager> GetThreadManager()
        {
#if WPF
            Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
#endif
#if SILVERLIGHT
            var dispatcher = Deployment.Current.Dispatcher;
#endif
#if NETFX_CORE
            var dispatcher = Windows.UI.Xaml.Window.Current.Dispatcher;
#endif
#if TASKSUPPORT
            return
                BindingInfo<IThreadManager>.FromInstance(new ThreadManager(dispatcher,
                    TaskScheduler.FromCurrentSynchronizationContext(), TaskScheduler.Default));
#else
            return BindingInfo<IThreadManager>.FromInstance(new ThreadManager(dispatcher));
#endif
        }

        /// <summary>
        ///     Gets the <see cref="IViewModelSettings" /> which will be used in all view models by default.
        /// </summary>
        /// <returns>
        ///     An instance of <see cref="IViewModelSettings" />.
        /// </returns>
        protected virtual BindingInfo<IViewModelSettings> GetSettings()
        {
            if (_settings != null)
                return BindingInfo<IViewModelSettings>.FromInstance(_settings);
            return BindingInfo<IViewModelSettings>.FromInstance(new DefaultViewModelSettings());
        }

        /// <summary>
        ///     Gets the <see cref="IViewModelWrapperProvider" /> which will be used by default.
        /// </summary>
        /// <returns>An instance of <see cref="IViewModelWrapperProvider" />.</returns>
        protected virtual BindingInfo<IViewModelWrapperProvider> GetViewModelWrapperProvider()
        {
            return BindingInfo<IViewModelWrapperProvider>.Empty;
        }

        /// <summary>
        ///     Gets the <see cref="IEventAggregator" /> which will be used by default.
        /// </summary>
        /// <returns>An instance of <see cref="IEventAggregator" />.</returns>
        protected virtual BindingInfo<IEventAggregator> GetEventAggregator()
        {
            return BindingInfo<IEventAggregator>.FromInstance(new EventAggregator());
        }

        /// <summary>
        ///     Gets an assemblies which contains views.
        /// </summary>
        /// <returns>
        ///     A series instances of <see cref="Assembly" />.
        /// </returns>
        protected virtual IList<Assembly> GetViewAssemblies()
        {
            if (_viewAssemblies != null)
                return _viewAssemblies;
#if !NETFX_CORE
            return MvvmUtilsInternal.GetAllAssemblies();
#else
            Should.MethodBeSupported(Application.Current != null, "GetViewAssemblies()");
            return new[]
            {
// ReSharper disable once PossibleNullReferenceException
                Application.Current.GetType().GetTypeInfo().Assembly
            };
#endif
        }

        #endregion
    }
}